{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9bdc99ef",
   "metadata": {},
   "source": [
    "# WebBaseLoader"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86a66f0f",
   "metadata": {},
   "source": [
    "`WebBaseLoader` 는 웹 기반 문서를 로드하는 로더입니다. \n",
    "\n",
    "`bs4` 라이브러리를 사용하여 웹 페이지를 파싱합니다. \n",
    "\n",
    "- `bs4.SoupStrainer` 를 사용하여 파싱할 요소를 지정합니다. \n",
    "- `bs_kwargs` 매개변수를 사용하여 `bs4.SoupStrainer` 의 추가적인 인수를 지정합니다. \n",
    "\n",
    "**참고**\n",
    "\n",
    "- [API 도큐먼트](https://api.python.langchain.com/en/latest/document_loaders/langchain_community.document_loaders.web_base.WebBaseLoader.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6c035b53",
   "metadata": {},
   "outputs": [],
   "source": [
    "import bs4\n",
    "from langchain_community.document_loaders import WebBaseLoader\n",
    "\n",
    "# 뉴스기사 내용을 로드합니다.\n",
    "loader = WebBaseLoader(\n",
    "    web_paths=(\"https://n.news.naver.com/article/437/0000378416\",),\n",
    "    bs_kwargs=dict(\n",
    "        parse_only=bs4.SoupStrainer(\n",
    "            \"div\",\n",
    "            attrs={\"class\": [\"newsct_article _article_body\", \"media_end_head_title\"]},\n",
    "        )\n",
    "    ),\n",
    "    header_template={\n",
    "        \"User_Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36\",\n",
    "    },\n",
    ")\n",
    "\n",
    "docs = loader.load()\n",
    "print(f\"문서의 수: {len(docs)}\")\n",
    "docs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "509f6456",
   "metadata": {},
   "source": [
    "SSL 인증 오류를 우회하기 위해, `\"verify\"` 옵션을 설정할 수 있습니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86fe1cc5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ssl 인증 우회\n",
    "loader.requests_kwargs = {\"verify\": True}\n",
    "\n",
    "# 데이터 로드\n",
    "docs = loader.load()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df1569c8",
   "metadata": {},
   "source": [
    "여러 웹페이지를 한 번에 로드할 수도 있습니다. 이를 위해 **urls**의 리스트를 로더에 전달하면, 전달된 **urls**의 순서대로 문서 리스트를 반환합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61817858",
   "metadata": {},
   "outputs": [],
   "source": [
    "loader = WebBaseLoader(\n",
    "    web_paths=[\n",
    "        \"https://n.news.naver.com/article/437/0000378416\",\n",
    "        \"https://n.news.naver.com/mnews/hotissue/article/092/0002340014?type=series&cid=2000063\",\n",
    "    ],\n",
    "    bs_kwargs=dict(\n",
    "        parse_only=bs4.SoupStrainer(\n",
    "            \"div\",\n",
    "            attrs={\"class\": [\"newsct_article _article_body\", \"media_end_head_title\"]},\n",
    "        )\n",
    "    ),\n",
    "    header_template={\n",
    "        \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36\",\n",
    "    },\n",
    ")\n",
    "\n",
    "# 데이터 로드\n",
    "docs = loader.load()\n",
    "\n",
    "# 문서 수 확인\n",
    "print(len(docs))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "123d8302",
   "metadata": {},
   "source": [
    "웹에서 가져온 결과를 출력합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3c00dc9",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(docs[0].page_content[:500])\n",
    "print(\"===\" * 10)\n",
    "print(docs[1].page_content[:500])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20c355fc",
   "metadata": {},
   "source": [
    "여러 URL을 동시에 스크래핑하면 스크래핑 과정을 가속화할 수 있습니다.\n",
    "\n",
    "동시 요청에는 합리적인 제한이 있으며, 기본값은 초당 2회입니다. 서버 부하에 대해 걱정하지 않거나, 스크래핑하는 서버를 제어하는 경우라면 `requests_per_second` 매개변수를 변경하여 최대 동시 요청 수를 늘릴 수 있습니다. 이 방법은 스크래핑 속도를 높일 수 있지만, 서버로부터 차단될 수 있으므로 주의해야 합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b2e0824",
   "metadata": {},
   "outputs": [],
   "source": [
    "# jupyter notebook 에서만 실행(asyncio)\n",
    "import nest_asyncio\n",
    "\n",
    "nest_asyncio.apply()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61980942",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 초당 요청 수 설정\n",
    "loader.requests_per_second = 1\n",
    "\n",
    "# 비동기 로드\n",
    "docs = loader.aload()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a2b40dcf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 결과 출력\n",
    "docs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66c2831a",
   "metadata": {},
   "source": [
    "## 프록시 사용\n",
    "\n",
    "IP 차단을 우회하기 위해 때때로 프록시를 사용할 필요가 있을 수 있습니다. \n",
    "\n",
    "프록시를 사용하려면 로더(및 그 아래의 `requests`)에 프록시 딕셔너리를 전달할 수 있습니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "efa9df6d",
   "metadata": {},
   "outputs": [],
   "source": [
    "loader = WebBaseLoader(\n",
    "    \"https://www.google.com/search?q=parrots\",\n",
    "    proxies={\n",
    "        \"http\": \"http://{username}:{password}:@proxy.service.com:6666/\",\n",
    "        \"https\": \"https://{username}:{password}:@proxy.service.com:6666/\",\n",
    "    },\n",
    "    # 웹 기반 로더 초기화\n",
    "    # 프록시 설정\n",
    ")\n",
    "\n",
    "# 문서 로드\n",
    "docs = loader.load()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e2b06487",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-kr-lwwSZlnu-py3.11",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
